<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>VeoStart</title>
    <!-- Tailwind CSS for styling -->
    <script src="https://cdn.tailwindcss.com"></script>
    <!-- Google Fonts for typography -->
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;900&display=swap" rel="stylesheet">
    <style>
        /* --- Base and Custom Styles --- */
        body {
            font-family: 'Inter', sans-serif;
            background-color: #f0f2f5;
        }
        /* Style for the main tabs (Generator/Gallery) */
        .main-tab {
            transition: all 0.3s ease;
            color: #4a5568;
        }
        .main-tab-active {
            background-color: white;
            color: #4c51bf;
            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
        }
        /* Style for the active generator sub-tab (Text/Image) */
        .generator-tab-active {
            border-color: #4c51bf;
            color: #4c51bf;
            background-color: #eef2ff;
        }
        /* Style for the gallery category buttons */
        .gallery-category-button {
            transition: all 0.2s ease-in-out;
            color: #374151;
            background-color: #fff;
            border: 1px solid #d1d5db;
        }
        .gallery-category-button:hover {
            background-color: #f9fafb;
            border-color: #6366f1;
        }
        .category-button-active {
            background-color: #4f46e5;
            color: white;
            border-color: #4f46e5;
        }
        /* Initially hide custom input fields and gallery sections */
        .custom-input, .gallery-examples {
            display: none;
        }
        /* Hover effect for cards in the gallery */
        .card-hover:hover {
            transform: translateY(-5px);
            box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
            transition: all 0.3s ease;
        }
        /* Smooth scrolling for gallery sliders */
        .slider-container {
            scroll-behavior: smooth;
        }
        .slider-item {
            scroll-snap-align: start;
        }
        /* Container to maintain aspect ratio for video thumbnails */
        .video-container {
            position: relative;
            padding-bottom: 56.25%; /* 16:9 aspect ratio */
            height: 0;
            overflow: hidden;
            width: 100%;
            background-color: #1f2937; 
        }
        .video-container img {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            object-fit: cover;
            transition: opacity 0.3s ease;
        }
        /* Dim the thumbnail on hover to make the play icon stand out */
        .card-hover:hover .video-container img {
            opacity: 0.8;
        }
        /* Play icon overlay for video thumbnails */
        .play-icon {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 60px;
            height: 60px;
            background-color: rgba(0, 0, 0, 0.5);
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: transform 0.3s ease;
            pointer-events: none;
        }
        .card-hover:hover .play-icon {
            transform: translate(-50%, -50%) scale(1.1);
        }
        .play-icon svg {
            width: 30px;
            height: 30px;
            color: white;
        }
    </style>
</head>
<body class="text-gray-800">

    <!-- === HEADER SECTION === -->
    <header class="bg-gradient-to-r from-gray-800 to-gray-900 text-white shadow-2xl">
        <div class="container mx-auto px-4 sm:px-6 lg:px-8 py-8">
            <h1 class="text-4xl md:text-5xl font-black tracking-tight">VeoStart</h1>
            <p class="mt-2 text-lg text-gray-300">Your Veo prompting assistant</p>
        </div>
    </header>

    <!-- === MAIN CONTENT === -->
    <main class="container mx-auto px-4 sm:px-6 lg:px-8 py-8">

        <!-- Main navigation tabs between Prompt Generator and Prompt Gallery -->
        <div class="flex space-x-2 bg-gray-200 p-1.5 rounded-xl mb-8">
            <button id="generator-main-tab" class="main-tab flex-1 py-2.5 px-4 font-bold rounded-lg text-sm" onclick="showMainTab('generator')">
                <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 inline-block mr-2" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M11.3 1.046A1 1 0 0112 2v5h4a1 1 0 01.82 1.573l-7 10A1 1 0 018 18v-5H4a1 1 0 01-.82-1.573l7-10a1 1 0 011.12-.38z" clip-rule="evenodd" /></svg>
                Prompt Generator
            </button>
            <button id="gallery-main-tab" class="main-tab flex-1 py-2.5 px-4 font-bold rounded-lg text-sm" onclick="showMainTab('gallery')">
                <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 inline-block mr-2" viewBox="0 0 20 20" fill="currentColor"><path d="M7 3a1 1 0 000 2h6a1 1 0 100-2H7zM4 7a1 1 0 011-1h10a1 1 0 110 2H5a1 1 0 01-1-1zM2 11a2 2 0 012-2h12a2 2 0 012 2v4a2 2 0 01-2 2H4a2 2 0 01-2-2v-4z" /></svg>
                Prompt Gallery
            </button>
        </div>

        <!-- === PROMPT GENERATOR SECTION (Initially hidden) === -->
        <div id="generator-content" style="display:none;">
            <section id="generator">
                <div class="bg-white rounded-2xl shadow-xl p-6 md:p-8">
                    <!-- API Key Input Section -->
                    <div class="mb-6 pb-6 border-b border-gray-200">
                        <label for="api-key-input" class="block text-sm font-medium text-gray-700 mb-1">Your Gemini API Key</label>
                        <div class="flex items-center gap-2">
                            <input type="password" id="api-key-input" class="flex-grow w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500" placeholder="Enter your API key">
                             <button id="validate-key-btn" onclick="validateApiKey()" class="py-2 px-4 bg-gray-600 text-white rounded-md font-semibold hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500 disabled:bg-gray-400">Validate</button>
                        </div>
                        <div id="api-key-status" class="text-xs mt-2 h-4"></div>
                        <p class="text-xs text-gray-500 mt-1">
                            This tool requires a Gemini API key to function. 
                            <a href="https://aistudio.google.com/app/apikey" target="_blank" rel="noopener noreferrer" class="text-indigo-600 hover:underline">Get your free key from Google AI Studio</a>. 
                            Your key is stored securely and is only accessible by you.
                        </p>
                    </div>

                    <!-- Sub-navigation tabs for the generator (Text-to-Video / Image-to-Video) -->
                    <div class="flex border-b mb-6 space-x-1">
                        <button id="text-to-video-tab" class="py-2 px-4 font-semibold border-b-2 rounded-t-lg" onclick="showGeneratorTab('text-to-video')">Text-to-Video</button>
                        <button id="image-to-video-tab" class="py-2 px-4 font-semibold text-gray-500 border-b-2 border-transparent rounded-t-lg" onclick="showGeneratorTab('image-to-video')">Image-to-Video</button>
                    </div>

                    <!-- Text-to-Video Generator Content -->
                    <div id="text-to-video-content">
                        <!-- Container for dynamically generated input fields -->
                        <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
                            <!-- JS will populate these divs -->
                        </div>
                        <div class="mt-8">
                            <button id="generate-text-prompt-btn" onclick="generateTextToVideoPrompt()" class="w-full flex items-center justify-center bg-indigo-600 text-white py-3 px-4 rounded-lg font-bold hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:bg-indigo-400 transition-all duration-300 transform hover:scale-105">
                                <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" /></svg>
                                Generate Prompt
                            </button>
                        </div>
                        <!-- Container for displaying the generated prompts -->
                        <div id="text-prompt-output-container" class="mt-6 p-4 bg-gray-50 rounded-lg border border-gray-200" style="display: none;">
                             <div id="text-short-prompt-section">
                                <h4 class="font-semibold mb-2 text-indigo-700">Generated Prompt:</h4>
                                <p id="text-prompt-output" class="text-gray-700"></p>
                             </div>
                             <div id="text-long-prompt-section" class="mt-4" style="display: none;">
                                <h4 class="font-semibold mb-2 text-green-700">Enhanced Prompt:</h4>
                                <p id="text-long-prompt-output" class="text-gray-700"></p>
                             </div>
                             <button id="generate-longer-text-prompt-btn" onclick="generateLongerPrompt('text')" class="mt-4 py-2 px-4 bg-green-600 text-white rounded-md font-semibold hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 disabled:bg-green-400" style="display: none;">
                                Generate Longer Prompt
                            </button>
                        </div>
                    </div>

                    <!-- Image-to-Video Generator Content (Initially hidden) -->
                    <div id="image-to-video-content" style="display:none;">
                         <p class="mb-4 text-sm text-gray-600">Upload an image and select motion and audio to add to the scene.</p>
                         <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
                            <div>
                                <h4 class="text-lg font-semibold text-gray-800 mb-2">1. Image & Motion</h4>
                                <div class="space-y-4">
                                    <div>
                                        <label for="image-upload" class="block text-sm font-medium text-gray-700 mb-1">Upload Image</label>
                                        <input type="file" id="image-upload" accept="image/*" class="w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-600 hover:file:bg-indigo-100"/>
                                        <div id="image-preview-container" class="mt-4 hidden">
                                            <img id="image-preview" src="#" alt="Image Preview" class="max-h-48 rounded-lg shadow-md mx-auto"/>
                                        </div>
                                    </div>
                                    <div id="image-motion-choices">
                                        <!-- JS will populate motion choices here -->
                                    </div>
                                </div>
                            </div>
                            <div>
                                 <h4 class="text-lg font-semibold text-gray-800 mb-2">2. Audio</h4>
                                <div id="image-audio-choices" class="space-y-4">
                                    <!-- JS populates audio choices here -->
                                </div>
                            </div>
                         </div>
                         <div class="mt-8">
                            <button id="generate-image-prompt-btn" onclick="generateImageToVideoPrompt()" class="w-full flex items-center justify-center bg-indigo-600 text-white py-3 px-4 rounded-lg font-bold hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:bg-indigo-400 transition-all duration-300 transform hover:scale-105">
                                <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z" /><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
                                Generate Prompt
                            </button>
                        </div>
                        <div id="image-prompt-output-container" class="mt-6 p-4 bg-gray-50 rounded-lg border border-gray-200" style="display: none;">
                            <div id="image-short-prompt-section">
                                <h4 class="font-semibold mb-2 text-indigo-700">Generated Prompt:</h4>
                                <p id="image-prompt-output" class="text-gray-700"></p>
                            </div>
                            <div id="image-long-prompt-section" class="mt-4" style="display: none;">
                               <h4 class="font-semibold mb-2 text-green-700">Enhanced Prompt:</h4>
                               <p id="image-long-prompt-output" class="text-gray-700"></p>
                            </div>
                            <button id="generate-longer-image-prompt-btn" onclick="generateLongerPrompt('image')" class="mt-4 py-2 px-4 bg-green-600 text-white rounded-md font-semibold hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 disabled:bg-green-400" style="display: none;">
                               Generate Longer Prompt
                           </button>
                        </div>
                    </div>
                </div>
            </section>
        </div>

        <!-- === PROMPT GALLERY SECTION === -->
        <div id="gallery-content">
            <section id="gallery" class="mb-12">
                 <h2 class="text-3xl font-bold mb-4">Prompt Gallery</h2>
                 <p class="text-gray-600 mb-8">Choose a category to browse video examples and the prompts that created them.</p>
                 <div id="gallery-categories" class="flex flex-wrap gap-3 mb-8">
                     <button class="gallery-category-button py-2 px-5 rounded-full font-semibold shadow-sm" onclick="showGalleryCategory('subject')">Subject, Scene & Action</button>
                     <button class="gallery-category-button py-2 px-5 rounded-full font-semibold shadow-sm" onclick="showGalleryCategory('camera')">Camera Work</button>
                     <button class="gallery-category-button py-2 px-5 rounded-full font-semibold shadow-sm" onclick="showGalleryCategory('style')">Visual & Temporal Styles</button>
                     <button class="gallery-category-button py-2 px-5 rounded-full font-semibold shadow-sm" onclick="showGalleryCategory('audio')">Audio</button>
                 </div>
                 <div id="gallery-sliders-container">
                     <!-- JS will populate sliders here -->
                 </div>
            </section>
        </div>
    </main>

    <!-- === FOOTER === -->
    <footer class="bg-gray-800 text-gray-400 mt-12">
        <div class="container mx-auto px-6 py-4 text-center text-sm">
            <p>Contact: Bakkali Wafae, wafaeb@google.com</p>
        </div>
    </footer>
    
    <!-- === SCRIPT SECTION === -->
    <script type="module">
        // Import Firebase modules for authentication and database
        import { initializeApp } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-app.js";
        import { getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-auth.js";
        import { getFirestore, doc, getDoc, setDoc } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-firestore.js";

        // --- Global Variables ---
        let db, auth, userId, appId; // Firebase-related variables

        // --- DATA OBJECTS ---
        
        // Data for Text-to-Video dropdowns and options
        const textVideoSelectData = {
             camera_angle: { label: "Camera Angles", options: ["Eye-Level Shot", "Low-Angle Shot", "High-Angle Shot", "Bird's-Eye View", "Top-Down Shot", "Worm's-Eye View", "Dutch Angle", "Canted Angle", "Close-Up", "Extreme Close-Up", "Medium Shot", "Full Shot", "Long Shot", "Wide Shot", "Establishing Shot", "Over-the-Shoulder Shot", "Point-of-View (POV) Shot"] },
             camera_movement: { label: "Camera Movements", options: ["Static Shot (or fixed)", "Pan (left)", "Pan (right)", "Tilt (up)", "Tilt (down)", "Dolly (In)", "Dolly (Out)", "Zoom (In)", "Zoom (Out)", "Truck (Left)", "Truck (Right)", "Pedestal (Up)", "Pedestal (Down)", "Crane Shot", "Aerial Shot", "Drone Shot", "Handheld", "Shaky Cam", "Whip Pan", "Arc Shot"] },
             lens_effect: { label: "Lens & Optical Effects", options: ["Wide-Angle Lens (e.g., 24mm)", "Telephoto Lens (e.g., 85mm)", "Shallow Depth of Field", "Bokeh", "Deep Depth of Field", "Lens Flare", "Rack Focus", "Fisheye Lens Effect", "Vertigo Effect (Dolly Zoom)"] },
             visual_style: { label: "Visual Style & Aesthetics", options: ["Photorealistic", "Cinematic", "Vintage", "Japanese anime style", "Claymation style", "Stop-motion animation", "In the style of Van Gogh", "Surrealist painting", "Monochromatic black and white", "Vibrant and saturated", "Film noir style", "High-key lighting", "Low-key lighting", "Golden hour glow", "Volumetric lighting", "Backlighting to create a silhouette"] },
             temporal_element: { label: "Temporal Elements", options: ["Slow-motion", "Fast-paced action", "Time-lapse", "Hyperlapse", "Pulsating light", "Rhythmic movement"] },
             sound_effects: { label: "Sound Effects & Ambience", options: ["Sound of a phone ringing", "Water splashing", "Soft house sounds", "Ticking clock", "City traffic and sirens", "Waves crashing", "Quiet office hum"] }
        };

        // Data for Image-to-Video dropdowns, reusing options from text-to-video where applicable
        const imageVideoData = {
            camera_motion: {
                label: "Camera Motion",
                options: [ "None", ...textVideoSelectData.camera_angle.options, ...textVideoSelectData.camera_movement.options, ...textVideoSelectData.lens_effect.options ]
            },
            subject_animation: {
                label: "Subject Animation",
                options: ["None", "The subject's head turns slowly", "The subject blinks slowly", "The subject's hair and clothes flutter gently in the wind", "A subtle smile appears on the subject's face"]
            },
            environmental_animation: {
                label: "Environmental Animation",
                options: ["None", "Fog rolls in slowly", "Rain starts to fall gently", "Leaves rustle in the wind", "Light changes subtly", "Reflections move on water"]
            },
            sound_effects: {
                label: "Sound Effects & Ambience", 
                options: textVideoSelectData.sound_effects.options 
            }
        };
       
        // Data for the Prompt Gallery, including titles, prompts, and YouTube video IDs for examples
        const galleryData = {
            subject: {
                title: "Subject, Scene & Action",
                examples: [
                    { title: "Complex Subject", prompt: "A hyper-realistic, cinematic portrait of a wise, androgynous shaman...draped in ceremonial robes...holding a gnarled wooden staff...", youtubeId: "GKOpOcs8IF8" },
                    { title: "Portrait", prompt: "A cinematic portrait of a woman looking thoughtfully out a window, with soft, natural light and beautiful bokeh.", youtubeId: "Ol66pK2N7L0" },
                    { title: "Sequencing of Actions", prompt: "A gloved hand carefully slices open the spine of an ancient, leather-bound book... then delicately extracts a tiny, metallic data chip... The character's eyes widen in alarm...", youtubeId: "EbCAqMF2DBo" },
                    { title: "Emotional Expression", prompt: "A close-up on a woman's face. Her expression shifts from neutral to a look of profound surprise and joy, her eyes widening and a smile forming.", youtubeId: "lYMjzZHykCo" }
                ]
            },
            camera: {
                title: "Camera Work",
                examples: [
                    { title: "Low Angle Shot", prompt: "Dynamic low-angle shot of a basketball player soaring for a slam dunk, stadium lights flaring.", youtubeId: "zCZ91E7tPeE" },
                    { title: "Drone Shot", prompt: "Sweeping aerial drone shot flying over a tropical island chain.", youtubeId: "gvPtt5f-kKc" },
                    { title: "Zoom In Shot", prompt: "A slow, dramatic zoom in on a mysterious, ancient compass lying on a dusty map...", youtubeId: "izn8VHHFy3c" },
                    { title: "Over-the-Shoulder", prompt: "An over-the-shoulder shot from behind a seasoned detective, looking at a nervous informant sitting across a table in a dimly lit interrogation room.", youtubeId: "z73bvXtUC_0" },
                    { title: "Rack Focus", prompt: "A medium shot of a detective's hand in the foreground, holding a single, spent bullet casing. The camera then performs a slow rack focus...", youtubeId: "-p6W4mCYuvc" },
                    { title: "Handheld Camera", prompt: "An intense handheld camera shot during a chaotic marketplace chase. The camera struggles to keep up, with jerky movements...", youtubeId: "csnE4FNogJQ" }
                ]
            },
            style: {
                title: "Visual & Temporal Styles",
                examples: [
                    { title: "Anime Style", prompt: "A dynamic scene in a vibrant Japanese anime style. A magical girl with silver hair and glowing blue eyes walks in a forest...", youtubeId: "vu2ZFw-9ZMI" },
                    { title: "Lens Flare", prompt: "A cinematic shot of a couple embracing on a beach at sunset. As the sun dips below the horizon..., a warm, anamorphic lens flare streaks across the frame.", youtubeId: "jY3gQS73614" },
                    { title: "Jump Cut", prompt: "A person sitting in the same position but wearing different outfits, with sharp jump cuts between each outfit change...", youtubeId: "d-cGj3kAnsQ" },
                    { title: "Time-Lapse", prompt: "A time-lapse of a bustling city skyline as day transitions to night...the city lights begin to twinkle on, with streaks of car headlights...", youtubeId: "CT0PIze9w0Y" },
                    { title: "Cyberpunk Lighting", prompt: "A hyper-realistic, cinematic shot of a rain-slicked cyberpunk alleyway at midnight. Pulsating pink and teal neon signs reflect off puddles...", youtubeId: "bKIZ-pdCJnA" },
                    { title: "Vintage Style", prompt: "A vintage 1920s street scene, sepia toned, film grain, with characters in period attire.", youtubeId: "WJwj6y7p8SI" }
                ]
            },
            audio: {
                title: "Audio",
                examples: [
                    { title: "Ambient Noise", prompt: "A static, wide shot of a vast, ancient library at night. The only sounds are the soft, rhythmic ticking of a grandfather clock, the gentle rustle of turning pages...", youtubeId: "WsXXBDhO7l0" },
                    { title: "Dialogue", prompt: "A medium shot in a dimly lit interrogation room. The seasoned detective says: Your story has holes. The nervous informant, sweating under a single bare bulb, replies: I'm telling you everything I know. The only other sounds are the slow, rhythmic ticking of a wall clock and the faint sound of rain against the window", youtubeId: "yGcMvkFK9Zo" }
                ]
            }
        };
        
        // --- UTILITY FUNCTIONS ---

        /**
         * Converts a file object to a base64 encoded string.
         * @param {File} file The file to convert.
         * @returns {Promise<string>} A promise that resolves with the base64 string.
         */
        const toBase64 = file => new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onload = () => resolve(reader.result);
            reader.onerror = error => reject(error);
        });

        // --- FIREBASE AND AUTHENTICATION ---

        /**
         * Initializes the Firebase app, sets up authentication, and loads the user's API key.
         */
        async function initializeFirebase() {
            // Get app ID and Firebase config from the global scope (provided by the environment)
            appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id';
            const firebaseConfigStr = typeof __firebase_config !== 'undefined' ? __firebase_config : '{}';
            
            if (firebaseConfigStr === '{}') {
                console.warn("Firebase config is empty. Firestore features will be disabled.");
                return;
            }

            try {
                const firebaseConfig = JSON.parse(firebaseConfigStr);
                const app = initializeApp(firebaseConfig);
                db = getFirestore(app);
                auth = getAuth(app);

                // Wait for authentication to complete
                await new Promise((resolve, reject) => {
                    const unsubscribe = onAuthStateChanged(auth, async (user) => {
                        unsubscribe(); // Stop listening after the first auth state change
                        if (user) {
                            userId = user.uid;
                            await loadApiKeyFromFirestore();
                        } else {
                            try {
                                // Sign in with a custom token if provided, otherwise sign in anonymously
                                const token = typeof __initial_auth_token !== 'undefined' ? __initial_auth_token : null;
                                if (token) {
                                    await signInWithCustomToken(auth, token);
                                } else {
                                    await signInAnonymously(auth);
                                }
                            } catch (error) {
                                console.error("Authentication error:", error);
                                reject(error);
                            }
                        }
                        resolve();
                    }, reject);
                });
            } catch (error) {
                console.error("Firebase initialization failed:", error);
            }
        }

        /**
         * Saves the user's API key securely to their private Firestore document.
         * @param {string} apiKey The Gemini API key to save.
         */
        async function saveApiKeyToFirestore(apiKey) {
            if (!db || !userId) return; // Do nothing if Firebase is not initialized
            try {
                const apiKeyDocRef = doc(db, 'artifacts', appId, 'users', userId, 'settings', 'api');
                await setDoc(apiKeyDocRef, { key: apiKey });
            } catch (error) {
                console.error("Error saving API key:", error);
            }
        }

        /**
         * Loads the user's API key from Firestore and populates the input field.
         */
        async function loadApiKeyFromFirestore() {
            if (!db || !userId) return;
            try {
                const apiKeyDocRef = doc(db, 'artifacts', appId, 'users', userId, 'settings', 'api');
                const docSnap = await getDoc(apiKeyDocRef);
                if (docSnap.exists() && docSnap.data().key) {
                    document.getElementById('api-key-input').value = docSnap.data().key;
                    await validateApiKey(); // Automatically validate the loaded key
                }
            } catch (error) {
                console.error("Error loading API key:", error);
            }
        }
        
        // --- DYNAMIC UI AND FORM GENERATION ---

        /**
         * Resets the prompt output UI for a given type ('text' or 'image').
         * Hides output containers, clears text, and resets buttons.
         * @param {string} type - The type of UI to reset ('text' or 'image').
         */
        function resetPromptUI(type) {
            const isText = type === 'text';
            const container = document.getElementById(isText ? 'text-prompt-output-container' : 'image-prompt-output-container');
            const longSection = document.getElementById(isText ? 'text-long-prompt-section' : 'image-long-prompt-section');
            const longOutput = document.getElementById(isText ? 'text-long-prompt-output' : 'image-long-prompt-output');
            const longerBtn = document.getElementById(isText ? 'generate-longer-text-prompt-btn' : 'generate-longer-image-prompt-btn');

            if (container) container.style.display = 'none';
            if (longSection) longSection.style.display = 'none';
            if (longOutput) longOutput.textContent = '';
            if (longerBtn) {
                longerBtn.style.display = 'none';
                longerBtn.disabled = false;
                longerBtn.innerHTML = 'Generate Longer Prompt';
            }
        }

        /**
         * Creates and returns a select (dropdown) component with a label.
         * @param {string} id - The base ID for the select element.
         * @param {object} data - An object containing the label and options array.
         * @param {boolean} hasCustomOption - Whether to include a "Custom..." option.
         * @param {boolean} hasNoneOption - Whether to include a "-- None --" option.
         * @returns {HTMLElement} The container div for the select component.
         */
        window.createSelectComponent = function(id, data, hasCustomOption = true, hasNoneOption = false) {
            const container = document.createElement('div');
            container.className = 'prompt-component';
            
            const label = document.createElement('label');
            label.htmlFor = id;
            label.className = 'block text-sm font-medium text-gray-700 mb-1';
            label.textContent = data.label;

            const select = document.createElement('select');
            select.id = id;
            select.name = id;
            select.className = 'w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500';
            const type = id.includes('image-') ? 'image' : 'text';
            select.addEventListener('change', () => {
                handleSelectChange(select);
                resetPromptUI(type);
            });

            let optionsHtml = '';
            if (hasNoneOption) optionsHtml += '<option value="">-- None --</option>';
            data.options.forEach(opt => optionsHtml += `<option value="${opt}">${opt}</option>`);
            if (hasCustomOption) optionsHtml += '<option value="custom">Custom...</option>';
            select.innerHTML = optionsHtml;
            
            container.appendChild(label);
            container.appendChild(select);

            if (hasCustomOption) {
                 const customInput = document.createElement('input');
                 customInput.type = 'text';
                 customInput.id = `${id}-custom`;
                 customInput.className = 'custom-input w-full p-2 mt-2 border border-gray-300 rounded-md shadow-sm';
                 customInput.placeholder = 'Enter custom value...';
                 customInput.addEventListener('input', () => resetPromptUI(type));
                 container.appendChild(customInput);
            }
            return container;
        }

        /**
         * Creates and returns a text input component with a label.
         * @param {string} id - The ID for the input element.
         * @param {string} labelText - The text for the label.
         * @param {string} placeholder - The placeholder text for the input.
         * @returns {HTMLElement} The container div for the input component.
         */
        window.createInputComponent = function(id, labelText, placeholder) {
            const container = document.createElement('div');
            container.className = 'prompt-component';
            const label = document.createElement('label');
            label.htmlFor = id;
            label.className = 'block text-sm font-medium text-gray-700 mb-1';
            label.textContent = labelText;
            const input = document.createElement('input');
            input.type = 'text';
            input.id = id;
            input.className = 'w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500';
            input.placeholder = placeholder;
            const type = id.includes('image-') ? 'image' : 'text';
            input.addEventListener('input', () => resetPromptUI(type));
            container.appendChild(label);
            container.appendChild(input);
            return container;
        }
       
        /**
         * Populates the Text-to-Video form with dynamic input and select fields based on the `elementOrder` array.
         */
        function populateTextToVideoForm() {
            const container = document.querySelector('#text-to-video-content .grid');
            container.innerHTML = '';
            const elementOrder = [
                { type: 'input', id: 'subject-input', label: 'Subject', placeholder: 'e.g., A dog' },
                { type: 'input', id: 'action-input', label: 'Action', placeholder: 'e.g., running' },
                { type: 'input', id: 'scene-input', label: 'Scene / Context', placeholder: 'e.g., on a sunny beach' },
                { type: 'select', key: 'camera_angle' },
                { type: 'select', key: 'camera_movement' },
                { type: 'select', key: 'lens_effect' },
                { type: 'select', key: 'visual_style' },
                { type: 'select', key: 'temporal_element' },
                { type: 'select', key: 'sound_effects' },
                { type: 'input', id: 'dialogue-input', label: 'Dialogue', placeholder: `e.g., Let's go!` }
            ];
            elementOrder.forEach(el => {
                if (el.type === 'input') container.appendChild(createInputComponent(el.id, el.label, el.placeholder));
                else if (el.type === 'select') container.appendChild(createSelectComponent(el.key, textVideoSelectData[el.key], true, true));
            });
        }

        /**
         * Populates the Image-to-Video form with dynamic input and select fields for motion and audio.
         */
        function populateImageToVideoForm() {
            const motionContainer = document.getElementById('image-motion-choices');
            motionContainer.innerHTML = '';
            Object.keys(imageVideoData).forEach(key => {
                 if (key !== 'sound_effects') motionContainer.appendChild(createSelectComponent('image-' + key, imageVideoData[key], true, true));
            });
            const audioContainer = document.getElementById('image-audio-choices');
            audioContainer.innerHTML = '';
            audioContainer.appendChild(createSelectComponent('image-sound_effects', imageVideoData.sound_effects, true, true));
            audioContainer.appendChild(createInputComponent('image-dialogue-input', 'Dialogue', 'e.g., It is beautiful'));
        }

        // --- API AND PROMPT GENERATION LOGIC ---

        /**
         * Validates the provided Gemini API key by making a test call.
         * Updates the UI with the validation status and saves the key to Firestore on success.
         */
        window.validateApiKey = async function() {
            const apiKey = document.getElementById('api-key-input').value;
            const statusElement = document.getElementById('api-key-status');
            const validateBtn = document.getElementById('validate-key-btn');
            if (!apiKey) {
                statusElement.textContent = 'Please enter a key to validate.';
                statusElement.className = 'text-xs mt-2 h-4 text-yellow-600 font-semibold';
                return;
            }
            validateBtn.disabled = true;
            validateBtn.innerHTML = `<svg class="animate-spin h-5 w-5 mx-auto text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg>`;
            statusElement.textContent = '';
            const validationUrl = `https://generativelanguage.googleapis.com/v1beta/models?key=${apiKey}`;
            try {
                const response = await fetch(validationUrl);
                if (response.ok) {
                    statusElement.textContent = 'API Key is valid!';
                    statusElement.className = 'text-xs mt-2 h-4 text-green-600 font-semibold';
                    await saveApiKeyToFirestore(apiKey); 
                } else {
                    const error = await response.json();
                    statusElement.textContent = `Invalid Key: ${error.error.message || 'Check permissions.'}`;
                    statusElement.className = 'text-xs mt-2 h-4 text-red-600 font-semibold';
                }
            } catch (error) {
                statusElement.textContent = 'Validation failed. Check network or console.';
                statusElement.className = 'text-xs mt-2 h-4 text-red-600 font-semibold';
            } finally {
                validateBtn.disabled = false;
                validateBtn.textContent = 'Validate';
            }
        }

        /**
         * Calls the Gemini API with a system prompt and optional image data.
         * @param {string} systemPrompt - The instruction prompt for the model.
         * @param {string} apiKey - The user's Gemini API key.
         * @param {object|null} imageData - Optional image data { mimeType, base64 } for multimodal prompts.
         * @returns {Promise<string>} The text response from the API or an error message.
         */
        async function callGeminiApi(systemPrompt, apiKey, imageData = null) {
            if (!apiKey) {
                return "Error: API Key is missing. Please enter and validate your Gemini API key above.";
            }
            // Use a stable, public model for multimodal tasks.
            const model = 'gemini-1.5-flash-latest';
            const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`;
            
            // Construct the payload parts, including image data if it exists.
            const userParts = [{ text: systemPrompt }];
            if (imageData) {
                // The API expects the base64 data without the data:image/... prefix.
                const base64Data = imageData.base64.substring(imageData.base64.indexOf(',') + 1);
                userParts.push({
                    inlineData: {
                        mimeType: imageData.mimeType,
                        data: base64Data
                    }
                });
            }
            const payload = {
                contents: [{ role: "user", parts: userParts }]
            };

            try {
                const response = await fetch(apiUrl, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify(payload)
                });
                if (!response.ok) {
                    const errorBody = await response.json();
                    throw new Error(`API Error: ${errorBody.error.message || 'Unknown error'}`);
                }
                const result = await response.json();
                
                // Handle cases where the prompt was blocked for safety reasons.
                if (result.promptFeedback && result.promptFeedback.blockReason) {
                    return `Request blocked. Reason: ${result.promptFeedback.blockReason}.`;
                }
                // Handle successful responses.
                if (result.candidates && result.candidates[0]?.content?.parts[0]?.text) {
                    return result.candidates[0].content.parts[0].text.trim();
                } else {
                     if (result.candidates && result.candidates[0].finishReason === "SAFETY") {
                        return "Prompt generation failed due to safety settings. Please try different keywords or a different image.";
                    }
                    console.log("Unexpected API response:", result);
                    throw new Error("Unexpected API response structure or empty content.");
                }
            } catch (error) {
                console.error("Error calling Gemini API:", error);
                return `Error: ${error.message}`;
            }
        }

        /**
         * Generates a prompt for the Text-to-Video feature.
         * Gathers all keywords, calls the Gemini API, and displays the result.
         */
        window.generateTextToVideoPrompt = async function() {
            const generateBtn = document.getElementById('generate-text-prompt-btn');
            const originalBtnHTML = generateBtn.innerHTML;
            try {
                const outputContainer = document.getElementById('text-prompt-output-container');
                const outputElement = document.getElementById('text-prompt-output');
                const apiKey = document.getElementById('api-key-input').value;
                
                resetPromptUI('text');

                if (!apiKey) {
                     outputElement.textContent = "Please enter your Gemini API key above to generate a prompt.";
                     outputContainer.style.display = 'block';
                     return;
                }
                // Gather keywords from all text inputs and select elements.
                const keywords = [];
                ['subject-input', 'action-input', 'scene-input'].forEach(id => {
                    const value = document.getElementById(id).value;
                    if(value) keywords.push(value);
                });
                const dialogue = document.getElementById('dialogue-input').value;
                if(dialogue) keywords.push(`A character says: '${dialogue}'`);
                Object.keys(textVideoSelectData).forEach(key => {
                    const value = getSelectValue(key);
                    if (value) keywords.push(value);
                });

                if (keywords.length === 0) {
                    outputElement.textContent = "Please provide at least one keyword, style, or effect.";
                    outputContainer.style.display = 'block';
                    return;
                }
                
                // Update UI to show loading state.
                generateBtn.disabled = true;
                generateBtn.innerHTML = `<svg class="animate-spin h-5 w-5 mr-3" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg> Generating...`;
                outputContainer.style.display = 'block';
                outputElement.textContent = 'Crafting the optimal prompt...';
                
                // Construct the system prompt and call the API.
                const systemPrompt = `You are an expert video prompt engineer for Google's Veo model. Your task is to construct the most effective and optimal prompt string using the following keywords. Every single keyword MUST be included. Synthesize them into a single, cohesive, and cinematic instruction. Do not add any new core concepts. Output ONLY the final prompt string, without any introduction or explanation. Mandatory Keywords: [${keywords.join(', ')}]`;
                const result = await callGeminiApi(systemPrompt, apiKey);
                
                // Display the result and the "enhance" button on success.
                outputElement.textContent = result;
                if (!result.startsWith("Error:") && !result.startsWith("Request blocked")) {
                    document.getElementById('generate-longer-text-prompt-btn').style.display = 'block';
                }
            } catch (error) {
                console.error("An unexpected error occurred in generateTextToVideoPrompt: ", error);
                document.getElementById('text-prompt-output').textContent = "An unexpected error occurred. Please try again.";
            } finally {
                // IMPORTANT: Ensure the button is always reset, even if an error occurs.
                generateBtn.disabled = false;
                generateBtn.innerHTML = originalBtnHTML;
            }
        }
       
        /**
         * Generates a prompt for the Image-to-Video feature.
         * Gathers the uploaded image and keywords, calls the multimodal Gemini API, and displays the result.
         */
        window.generateImageToVideoPrompt = async function() {
            const generateBtn = document.getElementById('generate-image-prompt-btn');
            const originalBtnHTML = generateBtn.innerHTML;
            try {
                const outputContainer = document.getElementById('image-prompt-output-container');
                const outputElement = document.getElementById('image-prompt-output');
                const apiKey = document.getElementById('api-key-input').value;
                const imageFile = document.getElementById('image-upload').files[0];
                
                resetPromptUI('image');

                if (!apiKey) {
                     outputElement.textContent = "Please enter your Gemini API key above to generate a prompt.";
                     outputContainer.style.display = 'block';
                     return;
                }
                
                if (!imageFile) {
                    outputElement.textContent = "Please upload an image first.";
                    outputContainer.style.display = 'block';
                    return;
                }

                const keywords = [];
                Object.keys(imageVideoData).forEach(key => {
                     const value = getSelectValue('image-' + key);
                     if (value && value.toLowerCase() !== 'none') keywords.push(value);
                });
                const dialogue = document.getElementById('image-dialogue-input').value;
                if(dialogue) keywords.push(`A character says: '${dialogue}'`);
                
                if (keywords.length === 0) {
                    outputElement.textContent = "Please select at least one motion or audio effect.";
                    outputContainer.style.display = 'block';
                    return;
                }
                
                generateBtn.disabled = true;
                generateBtn.innerHTML = `<svg class="animate-spin h-5 w-5 mr-3" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg> Generating...`;
                outputContainer.style.display = 'block';
                outputElement.textContent = 'Crafting the optimal prompt...';
                
                const base64DataWithPrefix = await toBase64(imageFile);
                const imageData = {
                    mimeType: imageFile.type,
                    base64: base64DataWithPrefix
                };
                
                const systemPrompt = `You are an expert prompt engineer for Google's Veo model. Analyze the provided image and combine its content with the following motion and audio keywords to generate a single, cohesive, and cinematic prompt. Integrate the image's subject and scene with the requested motion and audio effects. The final output must be ONLY the prompt itself, with no preamble. Mandatory Keywords: [${keywords.join(', ')}]`;
                const result = await callGeminiApi(systemPrompt, apiKey, imageData);
                
                outputElement.textContent = result;
                if (!result.startsWith("Error:") && !result.startsWith("Request blocked")) {
                    document.getElementById('generate-longer-image-prompt-btn').style.display = 'block';
                }
            } catch (error) {
                console.error("An unexpected error occurred in generateImageToVideoPrompt: ", error);
                document.getElementById('image-prompt-output').textContent = "An unexpected error occurred. Please try again.";
            } finally {
                generateBtn.disabled = false;
                generateBtn.innerHTML = originalBtnHTML;
            }
        }

        /**
         * Takes an existing prompt and enhances it using Gemini.
         * For image prompts, it sends the image along with the prompt for better context.
         * @param {string} type - 'text' or 'image' to determine which prompt to enhance.
         */
        window.generateLongerPrompt = async function(type) {
            const isText = type === 'text';
            const shortPromptElement = document.getElementById(isText ? 'text-prompt-output' : 'image-prompt-output');
            const longPromptSection = document.getElementById(isText ? 'text-long-prompt-section' : 'image-long-prompt-section');
            const longPromptOutputElement = document.getElementById(isText ? 'text-long-prompt-output' : 'image-long-prompt-output');
            const generateBtn = document.getElementById(isText ? 'generate-longer-text-prompt-btn' : 'generate-longer-image-prompt-btn');
            const apiKey = document.getElementById('api-key-input').value;
            const initialPrompt = shortPromptElement.textContent;
            let imageData = null;
            let result = '';

            if (!initialPrompt || initialPrompt.startsWith("Error:") || !apiKey) {
                longPromptOutputElement.textContent = "Error: Cannot generate longer prompt. Initial prompt or API key is missing.";
                longPromptSection.style.display = 'block';
                return;
            }
            
            generateBtn.disabled = true;
            generateBtn.innerHTML = `<svg class="animate-spin h-5 w-5 mr-2 -ml-1" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg> Enhancing...`;
            longPromptSection.style.display = 'block';
            longPromptOutputElement.textContent = "Crafting the optimal prompt...";

            let systemPrompt = `You are a video director. Your job is to enhance text prompts for 8 second videos to make them work well for an AI video generation tool. Enhance this prompt: "${initialPrompt}". Output ONLY the final prompt string, without any introduction, explanation, or quotation marks.`;

            // If it's an image prompt, get the image data to send with the request.
            if (type === 'image') {
                const imageFile = document.getElementById('image-upload').files[0];
                if (!imageFile) {
                    longPromptOutputElement.textContent = "Error: Image not found for enhancement.";
                    generateBtn.disabled = false;
                    generateBtn.innerHTML = 'Generate Longer Prompt';
                    return;
                }
                const base64DataWithPrefix = await toBase64(imageFile);
                imageData = {
                    mimeType: imageFile.type,
                    base64: base64DataWithPrefix
                };
                systemPrompt = `You are a video director. Your job is to enhance text prompts for 8 second videos to make them work well for an AI video generation tool. Look at the provided image and enhance this initial prompt based on the image's content: "${initialPrompt}". Output ONLY the final prompt string, without any introduction, explanation, or quotation marks.`;
            }
            
            result = await callGeminiApi(systemPrompt, apiKey, imageData);
            longPromptOutputElement.textContent = result;
            
            // On success, hide the button to prevent multiple enhancements of the same prompt.
            if (!result.startsWith("Error:") && !result.startsWith("Request blocked")) {
                generateBtn.style.display = 'none';
            } else {
                generateBtn.disabled = false;
                generateBtn.innerHTML = 'Generate Longer Prompt';
                longPromptSection.style.display = 'none';
            }
        }

        // --- UI NAVIGATION AND EVENT HANDLING ---

        /**
         * Creates and populates a gallery slider for a given category.
         * @param {string} categoryId - The ID of the category (e.g., 'subject').
         * @param {object} categoryData - The data object for the category.
         * @returns {HTMLElement} The fully constructed slider element.
         */
        function createSlider(categoryId, categoryData) {
            const sliderWrapper = document.createElement('div');
            sliderWrapper.id = `gallery-${categoryId}`;
            sliderWrapper.className = 'gallery-examples relative';
            const sliderContainer = document.createElement('div');
            sliderContainer.id = `slider-container-${categoryId}`;
            sliderContainer.className = 'slider-container flex overflow-x-auto snap-x snap-mandatory gap-6 pb-4';
            categoryData.examples.forEach(ex => {
                const card = document.createElement('a'); 
                card.href = ex.youtubeId ? `https://www.youtube.com/watch?v=${ex.youtubeId}` : '#';
                card.target = '_blank';
                card.rel = 'noopener noreferrer';
                card.className = 'slider-item snap-start flex-shrink-0 w-full sm:w-1/2 lg:w-1/3 bg-white rounded-xl shadow-lg overflow-hidden card-hover no-underline';
                const thumbnailUrl = ex.youtubeId ? `https://i.ytimg.com/vi/${ex.youtubeId}/hqdefault.jpg` : (ex.poster || 'https://placehold.co/600x400/1f2937/FFFFFF?text=No+Video');
                const mediaHtml = `
                    <div class="video-container">
                        <img src="${thumbnailUrl}" alt="${ex.title}">
                        ${ex.youtubeId ? `
                        <div class="play-icon">
                            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
                                <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8.002v3.996a1 1 0 001.555.832l3.197-2a1 1 0 000-1.664l-3.197-2z" clip-rule="evenodd" />
                            </svg>
                        </div>` : ''}
                    </div>
                `;
                card.innerHTML = `${mediaHtml}<div class="p-6"><h4 class="font-semibold text-lg mb-2 text-gray-800">${ex.title}</h4><p class="text-gray-700 text-sm">${ex.prompt}</p></div>`;
                sliderContainer.appendChild(card);
            });
            sliderWrapper.appendChild(sliderContainer);
            const prevButton = document.createElement('button');
            prevButton.className = 'absolute top-1/2 left-0 -translate-y-1/2 -translate-x-4 bg-white rounded-full p-2 shadow-md hover:bg-gray-100 z-10';
            prevButton.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" /></svg>`;
            prevButton.onclick = (e) => { e.stopPropagation(); sliderContainer.scrollLeft -= (sliderContainer.querySelector('.slider-item').offsetWidth + 24); };
            const nextButton = document.createElement('button');
            nextButton.className = 'absolute top-1/2 right-0 -translate-y-1/2 translate-x-4 bg-white rounded-full p-2 shadow-md hover:bg-gray-100 z-10';
            nextButton.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" /></svg>`;
            nextButton.onclick = (e) => { e.stopPropagation(); sliderContainer.scrollLeft += (sliderContainer.querySelector('.slider-item').offsetWidth + 24); };
            sliderWrapper.appendChild(prevButton);
            sliderWrapper.appendChild(nextButton);
            return sliderWrapper;
        }

        /**
         * Populates the entire prompt gallery with sliders for each category.
         */
        function populateGallery() {
            const container = document.getElementById('gallery-sliders-container');
            container.innerHTML = '';
            Object.keys(galleryData).forEach(key => container.appendChild(createSlider(key, galleryData[key])));
        }
        
        /**
         * Gets the value from a select element, handling the "Custom..." option.
         * @param {string} key - The ID of the select element.
         * @returns {string|null} The selected value.
         */
        window.getSelectValue = function(key) {
            const select = document.getElementById(key);
            if (!select) return null;
            let value = select.value;
            if (value === 'custom') {
                value = document.getElementById(`${key}-custom`).value;
            }
            return value || null;
        }

        /**
         * Handles the change event for a select element to show/hide the custom input field.
         * @param {HTMLElement} selectElement - The select element that changed.
         */
        window.handleSelectChange = function(selectElement) {
            const customInput = selectElement.parentElement.querySelector('.custom-input');
            if (customInput) {
                customInput.style.display = selectElement.value === 'custom' ? 'block' : 'none';
            }
        }
       
        /**
         * Shows the selected main tab ('generator' or 'gallery') and hides the other.
         * @param {string} tabName - The name of the tab to show.
         */
        window.showMainTab = function(tabName) {
            document.getElementById('gallery-content').style.display = tabName === 'gallery' ? 'block' : 'none';
            document.getElementById('generator-content').style.display = tabName === 'generator' ? 'block' : 'none';
            document.getElementById('gallery-main-tab').classList.toggle('main-tab-active', tabName === 'gallery');
            document.getElementById('generator-main-tab').classList.toggle('main-tab-active', tabName === 'generator');
            if (tabName === 'gallery' && !document.querySelector('.gallery-category-button.category-button-active')) {
                showGalleryCategory('subject'); 
            }
        }
       
        /**
         * Shows the selected gallery category and hides others.
         * @param {string} category - The name of the category to show.
         */
        window.showGalleryCategory = function(category) {
            document.querySelectorAll('.gallery-examples').forEach(el => el.style.display = 'none');
            document.querySelectorAll('.gallery-category-button').forEach(el => el.classList.remove('category-button-active'));
            const activeBtn = document.querySelector(`button[onclick="showGalleryCategory('${category}')"]`);
            if (activeBtn) {
                document.getElementById(`gallery-${category}`).style.display = 'block';
                activeBtn.classList.add('category-button-active');
            }
        }

        /**
         * Shows the selected generator sub-tab ('text-to-video' or 'image-to-video').
         * @param {string} tabName - The name of the sub-tab to show.
         */
        window.showGeneratorTab = function(tabName) {
            document.getElementById('text-to-video-content').style.display = tabName === 'text-to-video' ? 'block' : 'none';
            document.getElementById('image-to-video-content').style.display = tabName === 'image-to-video' ? 'block' : 'none';
            document.getElementById('text-to-video-tab').classList.toggle('generator-tab-active', tabName === 'text-to-video');
            document.getElementById('image-to-video-tab').classList.toggle('generator-tab-active', tabName === 'image-to-video');
            document.getElementById('text-to-video-tab').classList.toggle('text-gray-500', tabName !== 'text-to-video');
            document.getElementById('image-to-video-tab').classList.toggle('text-gray-500', tabName !== 'image-to-video');
        }
       
        /**
         * Main execution block that runs after the DOM is fully loaded.
         */
        document.addEventListener('DOMContentLoaded', async () => {
            // Initialize Firebase first to handle authentication and data loading.
            await initializeFirebase();
            
            // Populate the dynamic parts of the UI.
            populateTextToVideoForm();
            populateImageToVideoForm();
            populateGallery();
            
            // Set the initial UI state.
            showMainTab('generator');
            showGeneratorTab('text-to-video');
           
            // Set up the event listener for the image upload input.
            const imageUpload = document.getElementById('image-upload');
            if (imageUpload) {
                const imagePreview = document.getElementById('image-preview');
                const imagePreviewContainer = document.getElementById('image-preview-container');
                imageUpload.addEventListener('change', function() {
                    resetPromptUI('image');
                    if (this.files && this.files[0]) {
                        const reader = new FileReader();
                        reader.onload = function(e) {
                            imagePreview.src = e.target.result;
                            imagePreviewContainer.classList.remove('hidden');
                        }
                        reader.readAsDataURL(this.files[0]);
                    } else {
                         imagePreviewContainer.classList.add('hidden');
                    }
                });
            }
        });
    </script>
</body>
</html>

